/**
 * @file app\tasks\mobus\mobus_ops.c
 *
 * Copyright (C) 2023
 *
 * mobus_ops.c is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @author HinsShum hinsshum@qq.com
 *
 * @encoding utf-8
 */

/*---------- includes ----------*/
#include "inc/mobus_ops.h"
#include "errorno.h"
#include "options.h"
#include "resources.h"
#include "serial.h"
#include "simple_queue.h"
#include "timer.h"


/*---------- macro ----------*/
/*---------- type define ----------*/
/*---------- variable prototype ----------*/
/*---------- function prototype ----------*/
/*---------- variable ----------*/
static simple_queue_t q;
static void* serial = NULL;
static void* timer = NULL;

/*---------- function ----------*/
static bool _serial_init(uint32_t baudrate) {
    bool err = true;
    uint32_t old_baudrate = 0;

    serial = resources_get("dev_mobuscom");
    assert(serial);
    /* get old baudrate */
    device_ioctl(serial, IOCTL_SERIAL_GET_BAUDRATE, &old_baudrate);
    if (old_baudrate != baudrate) {
      /* set new baudrate */
        if (CY_EOK != device_ioctl(serial, IOCTL_SERIAL_SET_BAUDRATE, &baudrate)) {
            err = false;
        }
    }

    return err;
}

static void _serial_post(const uint8_t* pbuf, uint32_t length) {
    device_write(serial, (void*)pbuf, SERIAL_WRITE_CHANGE_DIR_AUTOMATICALLY,
        length);
}

static bool _timer_init(uint32_t t35_50us) {
    bool err = false;
    uint32_t us = t35_50us * 50;
    uint32_t freq = 0;

    timer = resources_get("dev_mobust35");
    assert(timer);
    /* calc timer frequency ���㶨ʱ��Ƶ�� */
    freq = (uint32_t)((float)1000000 / us);
    if (CY_EOK == device_ioctl(timer, IOCTL_TIMER_SET_FREQ, &freq)) {
        err = true;
    }

    return err;
}

static void _timer_ctrl(bool ctrl) {
    uint32_t cmd = (ctrl ? IOCTL_TIMER_ENABLE : IOCTL_TIMER_DISABLE);

    device_ioctl(timer, cmd, NULL);
}

static bool _event_init(void) {
    q = simple_queue_new(10, sizeof(serial_mac_evt_t));
    assert(q);

    return (q != NULL);
}

static bool _event_post(serial_mac_evt_t evt) {
    return simple_queue_push(q, &evt);
}

static bool _event_get(serial_mac_evt_t* evt) {
    assert(evt);
    return simple_queue_pop(q, evt);
}

void mobus_ops_get(struct serial_mac_ops* ops) {
    assert(ops);
    ops->halfduplex.difs = __ms2ticks(4);
    ops->halfduplex.tx_type = SERIAL_MAC_TX_TYPE_POLLING;
    ops->halfduplex.serial_init = _serial_init;
    ops->halfduplex.serial_post = _serial_post;
    ops->halfduplex.serial_byte_posted = NULL;
    ops->halfduplex.timer_init = _timer_init;
    ops->halfduplex.timer_ctrl = _timer_ctrl;
    ops->halfduplex.event_init = _event_init;
    ops->halfduplex.event_post = _event_post;
    ops->halfduplex.event_get = _event_get;
}